namespace tb
{

	// ================================
	// Constructors
	// ================================

	template <typename C>
	TB_INLINE StringBase<C>::StringBase()
	{
		m_Length = -1;
		m_Maximum = -1;
		m_Data = NULL;

		_AppendSingle = &StringBase<C>::_AppendDynSingle;
		_AppendDouble = &StringBase<C>::_AppendDynDouble;
	}

	template <typename C>
	TB_INLINE StringBase<C>::StringBase(int a_Maximum)
	{
		m_Length = 0;
		m_Maximum = a_Maximum;
		m_Data = new C[m_Maximum];
		StringHelper::Clear<C>(m_Data, m_Maximum);

		_AppendSingle = &StringBase<C>::_AppendFixedSingle;
		_AppendDouble = &StringBase<C>::_AppendFixedDouble;
	}

	// single width

	template <typename C>
	TB_INLINE StringBase<C>::StringBase(const char* a_String)
	{
		m_Length = StringHelper::GetLength<char>(a_String);
		m_Maximum = m_Length + 1;
		m_Data = new C[m_Maximum];
		StringHelper::Clear<C>(m_Data, m_Maximum);

		StringHelper::Copy<C, char>(m_Data, a_String, m_Length);

		_AppendSingle = &StringBase<C>::_AppendDynSingle;
		_AppendDouble = &StringBase<C>::_AppendDynDouble;
	}

	template <typename C>
	TB_INLINE StringBase<C>::StringBase(const char* a_String, int a_Maximum)
	{
		m_Maximum = a_Maximum;
		m_Data = new C[m_Maximum];
		m_Length = StringHelper::GetLength<char>(a_String);
		m_Length = (m_Length >= m_Maximum) ? (m_Maximum - 1) : m_Length;
		StringHelper::Clear<C>(m_Data, m_Maximum);

		StringHelper::Copy<C, char>(m_Data, a_String, m_Length);

		_AppendSingle = &StringBase<C>::_AppendFixedSingle;
		_AppendDouble = &StringBase<C>::_AppendFixedDouble;
	}

	template <typename C>
	TB_INLINE StringBase<C>::StringBase(const wchar_t* a_String)
	{
		m_Length = StringHelper::GetLength<wchar_t>(a_String);
		m_Maximum = m_Length + 1;
		m_Data = new C[m_Maximum];
		StringHelper::Clear<C>(m_Data, m_Maximum);

		StringHelper::Copy<C, wchar_t>(m_Data, a_String, m_Length);

		_AppendSingle = &StringBase<C>::_AppendFixedSingle;
		_AppendDouble = &StringBase<C>::_AppendFixedDouble;
	}

	template <typename C>
	TB_INLINE StringBase<C>::StringBase(const wchar_t* a_String, int a_Maximum)
	{
		m_Maximum = a_Maximum;
		m_Data = new C[m_Maximum];
		m_Length = StringHelper::GetLength<wchar_t>(a_String);
		m_Length = (m_Length > m_Maximum) ? (m_Maximum - 1) : m_Length;
		StringHelper::Clear<C>(m_Data, m_Maximum);

		StringHelper::Copy<C, wchar_t>(m_Data, a_String, m_Length);

		_AppendSingle = &StringBase<C>::_AppendFixedSingle;
		_AppendDouble = &StringBase<C>::_AppendFixedDouble;
	}

	template<typename C>
	TB_INLINE StringBase<C>::StringBase(const StringBase<char>& a_Other)
	{
		m_Maximum = a_Other.GetMaximum();

		_AppendSingle = &StringBase<C>::_AppendDynSingle;
		_AppendDouble = &StringBase<C>::_AppendDynDouble;

		if (m_Maximum > -1)
		{
			m_Length = 0;
			m_Data = new C[m_Maximum];
			StringHelper::Clear<C>(m_Data, m_Maximum);
			(this->*_AppendSingle)(a_Other.GetData());
		}
		else
		{
			m_Length = -1;
			m_Data = NULL;
		}
	}

	template<typename C>
	TB_INLINE StringBase<C>::StringBase(const StringBase<wchar_t>& a_Other)
	{
		m_Maximum = a_Other.GetMaximum();

		_AppendSingle = &StringBase<C>::_AppendDynSingle;
		_AppendDouble = &StringBase<C>::_AppendDynDouble;
		
		if (m_Maximum > -1)
		{
			m_Length = 0;
			m_Data = new C[m_Maximum];
			StringHelper::Clear<C>(m_Data, m_Maximum);
			(this->*_AppendDouble)(a_Other.GetData());
		}
		else
		{
			m_Length = -1;
			m_Data = NULL;
		}
	}

	template <typename C>
	TB_INLINE StringBase<C>::~StringBase()
	{
		if (m_Data) { delete [] m_Data; }
	}

	// ================================
	// Clear
	// ================================

	template <>
	TB_INLINE StringBase<char>& StringBase<char>::Clear()
	{
		if (m_Data)
		{
			StringHelper::Clear<char>(m_Data, m_Maximum);
		}

		m_Length = 0;

		return *this;
	}

	template <>
	TB_INLINE StringBase<wchar_t>& StringBase<wchar_t>::Clear()
	{
		if (m_Data)
		{
			StringHelper::Clear<wchar_t>(m_Data, m_Maximum);
		}

		m_Length = 0;

		return *this;
	}

	// ================================
	// Resize
	// ================================

	template <typename C>
	TB_INLINE StringBase<C>& StringBase<C>::Resize(int a_Maximum /*= -1*/)
	{
		if (!m_Data)
		{
			m_Maximum = (a_Maximum == -1) ? 4 : a_Maximum;
			m_Data = new C[m_Maximum];
			StringHelper::Clear<C>(m_Data, m_Maximum);
		}
		else
		{
			int newmax = (a_Maximum == -1) ? (m_Maximum * 2) : a_Maximum;

			C* temp = new C[newmax];
			StringHelper::Clear<C>(temp, newmax);
			if (m_Length > 0) { StringHelper::Copy(temp, m_Data, m_Length); }
			delete [] m_Data;
			m_Data = temp;

			/*C* temp = m_Data;

			m_Data = new C[newmax];
			StringHelper::Clear<C>(m_Data, newmax);
			if (m_Length > 0) { StringHelper::Copy(m_Data, temp, m_Length); }
			delete [] temp;*/

			m_Maximum = newmax;
		}
		
		return *this;
	}

	// ================================
	// Copy
	// ================================

	template <typename C>
	TB_INLINE StringBase<C>& StringBase<C>::Copy(const char* a_String, int a_CharacterCount /*= -1*/)
	{
		size_t length = (a_CharacterCount != -1) ? a_CharacterCount : StringHelper::GetLength(a_String);
		if (length == 0) { return *this; }

		if (length + 1 > m_Maximum)
		{
			if (m_Maximum == -1)
			{
				Resize(length + 1);
			}
			else
			{
				Resize();
			}
		}

		StringHelper::Copy(m_Data, a_String, length);
		m_Length = length;

		return *this;
	}

	// ================================
	// Format
	// ================================

	template <typename C>
	TB_INLINE StringBase<C>& StringBase<C>::Format(const char* a_Format, ...)
	{
		va_list args;
		va_start(args, a_Format);
		char buffer[0xFFFF];
		vsprintf(buffer, a_Format, args);
		va_end(args);

		Clear();
		(this->*_AppendSingle)(buffer);

		return *this;
	}

	template <typename C>
	TB_INLINE StringBase<C>& StringBase<C>::Format(const wchar_t* a_Format, ...)
	{
		va_list args;
		va_start(args, a_Format);
		wchar_t buffer[0xFFFF];
		vswprintf(buffer, 0xFFFF, a_Format, args);
		va_end(args);

		Clear();
		(this->*_AppendDouble)(buffer);

		return *this;
	}

	// ================================
	// Substrings
	// ================================

	template <typename C>
	TB_INLINE StringBase<C> StringBase<C>::GetSubLeft(int a_CharacterCount) const
	{
		StringBase<C> result;
		result.Resize(a_CharacterCount + 1);

		StringHelper::Copy(result.GetData(), m_Data, a_CharacterCount);
		result.m_Length = StringHelper::GetLength(result.GetData());

		return result;
	}

	template <typename C>
	TB_INLINE StringBase<C> StringBase<C>::GetSubMiddle(int a_Start, int a_CharacterCount /*= -1*/) const
	{
		StringBase<C> result;

		if (a_Start > m_Length)
		{
			return result;
		}

		int start = a_Start;
		int length = (a_CharacterCount == -1) ? (m_Length - start) : a_CharacterCount;
		result.Resize(length + 1);

		StringHelper::Copy(result.GetData(), m_Data + start, length);
		result.m_Length = StringHelper::GetLength(result.GetData());

		return result;
	}

	template <typename C>
	TB_INLINE StringBase<C> StringBase<C>::GetSubRight(int a_CharacterCount) const
	{
		StringBase<C> result;
		result.Resize(a_CharacterCount + 1);

		int start = (a_CharacterCount > m_Length) ? 0 : (m_Length - a_CharacterCount);
		StringHelper::Copy(result.GetData(), m_Data + start, a_CharacterCount);
		result.m_Length = StringHelper::GetLength(result.GetData());

		return result;
	}

	// ================================
	// Finding
	// ================================

	template <>
	TB_INLINE int StringBase<char>::FindLeft(char a_Character, int a_Occurance /* = 1*/) const
	{
		if (!m_Data || m_Length <= 0) { return -1; }

		int left = (a_Occurance < 1) ? 1 : a_Occurance;
		for (int i = 0; i < m_Length; i++)
		{
			if (m_Data[i] == a_Character && --left == 0) { return i; }
		}

		return -1;
	}

	template <>
	TB_INLINE int StringBase<wchar_t>::FindLeft(wchar_t a_Character, int a_Occurance /* = 1*/) const
	{
		if (!m_Data || m_Length <= 0) { return -1; }

		int left = (a_Occurance < 1) ? 1 : a_Occurance;
		for (int i = 0; i < m_Length; i++)
		{
			if (m_Data[i] == a_Character && --left == 0) { return i; }
		}

		return -1;
	}

	template <>
	TB_INLINE int StringBase<char>::FindRight(char a_Character, int a_Occurance /* = 1*/) const
	{
		if (!m_Data || m_Length <= 0) { return -1; }

		int left = (a_Occurance < 1) ? 1 : a_Occurance;
		for (int i = m_Length - 1; i >= 0; i--)
		{
			if (m_Data[i] == a_Character && --left == 0) { return i; }
		}

		return -1;
	}

	template <>
	TB_INLINE int StringBase<wchar_t>::FindRight(wchar_t a_Character, int a_Occurance /* = 1*/) const
	{
		if (!m_Data || m_Length <= 0) { return -1; }

		int left = (a_Occurance < 1) ? 1 : a_Occurance;
		for (int i = m_Length - 1; i >= 0; i--)
		{
			if (m_Data[i] == a_Character && --left == 0) { return i; }
		}

		return -1;
	}

	template <>
	TB_INLINE int StringBase<char>::FindNextLeft(char a_Character, int a_Start, int a_Occurance /*= 1*/) const
	{
		if (!m_Data || m_Length <= 0) { return -1; }

		if (a_Start < 0 || a_Start > m_Length) { return -1; }

		int left = (a_Occurance < 1) ? 1 : a_Occurance;
		for (int i = a_Start; i < m_Length; i++)
		{
			if (m_Data[i] == a_Character && --left == 0) { return i; }
		}

		return -1;
	}

	template <>
	TB_INLINE int StringBase<wchar_t>::FindNextLeft(wchar_t a_Character, int a_Start, int a_Occurance /*= 1*/) const
	{
		if (!m_Data || m_Length <= 0) { return -1; }

		if (a_Start < 0 || a_Start > m_Length) { return -1; }

		int left = (a_Occurance < 1) ? 1 : a_Occurance;
		for (int i = a_Start; i < m_Length; i++)
		{
			if (m_Data[i] == a_Character && --left == 0) { return i; }
		}

		return -1;
	}


	template <typename C>
	TB_INLINE StringBase<C> StringBase<C>::GetFindLeft(C a_Character, int a_Occurance /*= 1*/) const
	{
		int found = FindLeft(a_Character);
		if (found > 0) 
		{
			return GetSubLeft(found);
		}

		return StringBase<C>("");
	}

	// ================================
	// Push
	// ================================

	template <typename C>
	StringBase<C>& tb::StringBase<C>::Push(char a_Character)
	{
		char str[2] = { a_Character, 0 };
		return (this->*_AppendSingle)(str);
	}

	template <typename C>
	StringBase<C>& tb::StringBase<C>::Push(wchar_t a_Character)
	{
		wchar_t str[2] = { (wchar_t)a_Character, 0 };
		return (this->*_AppendDouble)(str);
	}

	// ================================
	// Appending
	// ================================

	template <typename C>
	StringBase<C>& StringBase<C>::Append(const StringBase<char>& a_String)
	{
		return (this->*_AppendSingle)(a_String.GetData());
	}

	template <typename C>
	StringBase<C>& StringBase<C>::Append(const StringBase<wchar_t>& a_String)
	{
		return (this->*_AppendDouble)(a_String.GetData());
	}

	template <typename C>
	StringBase<C>& StringBase<C>::Append(const char* a_String)
	{
		return (this->*_AppendSingle)(a_String);
	}

	template <typename C>
	StringBase<C>& StringBase<C>::Append(const wchar_t* a_String)
	{
		return (this->*_AppendDouble)(a_String);
	}

	// ================================
	// Appending dynamic
	// ================================

	// single width

	template<>
	TB_INLINE StringBase<char>& StringBase<char>::_AppendDynSingle(const char* a_String)
	{
		if (!a_String) { return *this; }

		int src_len = StringHelper::GetLength<char>(a_String);

		// check size

		if (m_Maximum == -1)
		{
			m_Maximum = src_len + 1;
			m_Data = new char[m_Maximum];
			StringHelper::Clear<char>(m_Data, m_Maximum);
			m_Length = 0;
		}

		int checklen = m_Length + src_len + 1;
		if (checklen > m_Maximum)
		{
			while (checklen > m_Maximum) { m_Maximum *= 2; }
			Resize(m_Maximum);
		}

		// append

		strcat(m_Data, a_String);
		
		// new length

		m_Length += src_len;

		return *this;
	}

	template<>
	TB_INLINE StringBase<char>& StringBase<char>::_AppendDynDouble(const wchar_t* a_String)
	{
		if (!a_String) { return *this; }

		int src_len = StringHelper::GetLength<wchar_t>(a_String);

		// check size

		if (m_Maximum == -1)
		{
			m_Maximum = src_len + 1;
			m_Data = new char[m_Maximum];
			StringHelper::Clear<char>(m_Data, m_Maximum);
			m_Length = 0;
		}

		int checklen = m_Length + src_len + 1;
		if (checklen > m_Maximum)
		{
			while (checklen > m_Maximum) { m_Maximum *= 2; }
			Resize(m_Maximum);
		}

		// append

		char* dst = m_Data + m_Length;
		const char* src = (const char*)a_String;
		for (int i = 0; i < src_len; i++)
		{
			*dst = *src;

			dst++;
			src += 2;
		}

		// new length

		m_Length += src_len;

		return *this;
	}

	// double width

	template<>
	TB_INLINE StringBase<wchar_t>& StringBase<wchar_t>::_AppendDynDouble(const wchar_t* a_String)
	{
		if (!a_String) { return *this; }

		int src_len = StringHelper::GetLength<wchar_t>(a_String);

		// check size

		if (m_Maximum == -1)
		{
			m_Maximum = src_len + 1;
			m_Data = new wchar_t[m_Maximum];
			StringHelper::Clear<wchar_t>(m_Data, m_Maximum);
			m_Length = 0;
		}

		int checklen = m_Length + src_len + 1;
		if (checklen > m_Maximum)
		{
			while (checklen > m_Maximum) { m_Maximum *= 2; }
			Resize(m_Maximum);
		}

		// append

		wcscat(m_Data, a_String);

		// new length

		m_Length += src_len;

		return *this;
	}

	template<>
	TB_INLINE StringBase<wchar_t>& StringBase<wchar_t>::_AppendDynSingle(const char* a_String)
	{
		if (!a_String) { return *this; }

		int src_len = StringHelper::GetLength<char>(a_String);

		// check size

		if (m_Maximum == -1)
		{
			m_Maximum = src_len + 1;
			m_Data = new wchar_t[m_Maximum];
			StringHelper::Clear<wchar_t>(m_Data, m_Maximum);
			m_Length = 0;
		}

		int checklen = m_Length + src_len + 1;
		if (checklen > m_Maximum)
		{
			while (checklen > m_Maximum) { m_Maximum *= 2; }
			Resize(m_Maximum);
		}

		// append

		char* dst = (char*)(m_Data + m_Length);
		char* src = (char*)a_String;
		for (int i = 0; i < src_len; i++)
		{
			*dst = *src;

			dst += 2;
			src++;
		}

		// new length

		m_Length += src_len;

		return *this;
	}

	// ================================
	// Appending fixed
	// ================================

	// single width

	template <>
	TB_INLINE StringBase<char>& tb::StringBase<char>::_AppendFixedSingle(const char* a_String)
	{
		if (!a_String) { return *this; }

		int src_len = StringHelper::GetLength<char>(a_String);
		int dst_len = m_Length;

		// check size

		if (src_len >= m_Maximum)
		{
			src_len = m_Maximum - 1;
		}

		if (dst_len + src_len >= m_Maximum)
		{
			src_len = (m_Maximum - dst_len);
			if (src_len == 0) { return *this; }
			src_len--;
		}

		// append

		char* dst = m_Data + m_Length;
		char* src = (char*)a_String;
		for (int i = 0; i < src_len; i++)
		{
			*dst++ = *src++;
		}

		// new length

		m_Length += src_len;
		
		return *this;
	}

	template <>
	TB_INLINE StringBase<char>& tb::StringBase<char>::_AppendFixedDouble(const wchar_t* a_String)
	{
		if (!a_String) { return *this; }

		int src_len = StringHelper::GetLength<wchar_t>(a_String);
		int dst_len = m_Length;

		// check size

		if (src_len >= m_Maximum)
		{
			src_len = m_Maximum - 1;
		}

		if (dst_len + src_len >= m_Maximum)
		{
			src_len = (m_Maximum - dst_len);
			if (src_len == 0) { return *this; }
			src_len--;
		}

		// append

		char* dst = m_Data + m_Length;
		char* src = (char*)a_String;
		for (int i = 0; i < src_len; i++)
		{
			*dst = *src;

			dst++;
			src += 2;
		}

		// new length

		m_Length += src_len;

		return *this;
	}

	// double width

	template <>
	TB_INLINE StringBase<wchar_t>& tb::StringBase<wchar_t>::_AppendFixedSingle(const char* a_String)
	{
		if (!a_String) { return *this; }

		int src_len = StringHelper::GetLength<char>(a_String);
		int dst_len = m_Length;

		// check size

		if (src_len >= m_Maximum)
		{
			src_len = m_Maximum - 1;
		}

		if (dst_len + src_len >= m_Maximum)
		{
			src_len = (m_Maximum - dst_len);
			if (src_len == 0) { return *this; }
			src_len--;
		}

		// append

		char* dst = (char*)(m_Data + m_Length);
		char* src = (char*)a_String;
		for (int i = 0; i < src_len; i++)
		{
			*dst = *src;

			dst += 2;
			src++;
		}

		// new length

		m_Length += src_len;

		return *this;
	}

	template <>
	TB_INLINE StringBase<wchar_t>& tb::StringBase<wchar_t>::_AppendFixedDouble(const wchar_t* a_String)
	{
		if (!a_String) { return *this; }

		int src_len = StringHelper::GetLength<wchar_t>(a_String);
		int dst_len = m_Length;

		// check size

		if (src_len >= m_Maximum)
		{
			src_len = m_Maximum - 1;
		}

		if (dst_len + src_len >= m_Maximum)
		{
			src_len = (m_Maximum - dst_len);
			if (src_len == 0) { return *this; }
			src_len--;
		}

		// append

		wchar_t* dst = m_Data + m_Length;
		const wchar_t* src = a_String;
		for (int i = 0; i < src_len; i++)
		{
			*dst++ = *src++;
		}

		// new length

		m_Length += src_len;

		return *this;
	}

	// ================================
	// Erasing
	// ================================

	template <typename C>
	TB_INLINE StringBase<C>& StringBase<C>::EraseLeft(int a_Start, int a_CharacterCount /*= -1*/)
	{
		if (a_Start < 0 || a_Start > m_Length) { return *this; }

		int end = (a_CharacterCount == -1 || a_Start + a_CharacterCount > m_Length) ? (m_Length) : (a_Start + a_CharacterCount);
		for (int i = a_Start; i < end; i++)
		{
			m_Data[i] = 0;
		}

		m_Length = a_Start;

		return *this;
	}

	template <typename C>
	TB_INLINE StringBase<C>& StringBase<C>::EraseRight(int a_Start, int a_CharacterCount /*= -1*/)
	{
		if (m_Length == 0 || a_Start < 0 || a_Start > m_Length) { return *this; }

		int start = m_Length - a_Start - 1;
		int end = (a_CharacterCount == -1 || start + a_CharacterCount > m_Length) ? (m_Length) : (start + a_CharacterCount);
		if (end > m_Length) { end = m_Length; }
		for (int i = start; i < end; i++)
		{
			m_Data[i] = 0;
		}

		m_Length = start;

		return *this;
	}

	// ================================
	// Operator []
	// ================================

	template <typename C>
	TB_INLINE C& StringBase<C>::operator [] (int a_Index)
	{
		if (a_Index < 0 || a_Index >= m_Length) { return m_Data[m_Length]; }

		return m_Data[a_Index];
	}

	template <typename C>
	TB_INLINE const C& StringBase<C>::operator [] (int a_Index) const
	{
		if (a_Index < 0 || a_Index >= m_Length) { return m_Data[m_Length]; }

		return m_Data[a_Index];
	}

	// ================================
	// Operator =
	// ================================

	// single width

	TB_INLINE StringBase<char>& StringBase<char>::operator = (const StringBase<char>& a_String)
	{
		Clear();
		return (this->*_AppendSingle)(a_String.GetData());
	}

	TB_INLINE StringBase<char>& StringBase<char>::operator = (const StringBase<wchar_t>& a_String)
	{
		Clear();
		return (this->*_AppendDouble)(a_String.GetData());
	}

	TB_INLINE StringBase<char>& StringBase<char>::operator = (const char *a_String)
	{
		Clear();
		return (this->*_AppendSingle)(a_String);
	}

	TB_INLINE StringBase<char>& StringBase<char>::operator = (const wchar_t* a_String)
	{
		Clear();
		return (this->*_AppendDouble)(a_String);
	}

	// double width

	TB_INLINE StringBase<wchar_t>& StringBase<wchar_t>::operator = (const StringBase<char>& a_String)
	{
		Clear();
		return (this->*_AppendSingle)(a_String.GetData());
	}

	TB_INLINE StringBase<wchar_t>& StringBase<wchar_t>::operator = (const StringBase<wchar_t>& a_String)
	{
		Clear();
		return (this->*_AppendDouble)(a_String.GetData());
	}

	TB_INLINE StringBase<wchar_t>& StringBase<wchar_t>::operator = (const char* a_String)
	{
		Clear();
		return (this->*_AppendSingle)(a_String);
	}

	TB_INLINE StringBase<wchar_t>& StringBase<wchar_t>::operator = (const wchar_t* a_String)
	{
		Clear();
		return (this->*_AppendDouble)(a_String);
	}

	// ================================
	// Operator +=
	// ================================

	// single width

	TB_INLINE StringBase<char>& StringBase<char>::operator += (const StringBase<char>& a_String)
	{
		return (this->*_AppendSingle)(a_String.GetData());
	}

	TB_INLINE StringBase<char>& StringBase<char>::operator += (const StringBase<wchar_t>& a_String)
	{
		return (this->*_AppendDouble)(a_String.GetData());
	}

	TB_INLINE StringBase<char>& StringBase<char>::operator += (const char* a_String)
	{
		return (this->*_AppendSingle)(a_String);
	}

	TB_INLINE StringBase<char>& StringBase<char>::operator += (const wchar_t* a_String)
	{
		return (this->*_AppendDouble)(a_String);
	}

	// double width

	TB_INLINE StringBase<wchar_t>& StringBase<wchar_t>::operator += (const StringBase<char>& a_String)
	{
		return (this->*_AppendSingle)(a_String.GetData());
	}

	TB_INLINE StringBase<wchar_t>& StringBase<wchar_t>::operator += (const StringBase<wchar_t>& a_String)
	{
		return (this->*_AppendDouble)(a_String.GetData());
	}

	TB_INLINE StringBase<wchar_t>& StringBase<wchar_t>::operator += (const char* a_String)
	{
		return (this->*_AppendSingle)(a_String);
	}

	TB_INLINE StringBase<wchar_t>& StringBase<wchar_t>::operator += (const wchar_t* a_String)
	{
		return (this->*_AppendDouble)(a_String);
	}

	// ================================
	// Operator +
	// ================================

	// single width

	TB_INLINE StringBase<char> StringBase<char>::operator + (const StringBase<char>& a_String) const
	{
		StringBase<char> result(m_Data);
		result.Append(a_String.GetData());
		return result;
	}

	TB_INLINE StringBase<char> StringBase<char>::operator + (const StringBase<wchar_t>& a_String) const
	{
		StringBase<char> result(m_Data);
		result.Append(a_String.GetData());
		return result;
	}

	TB_INLINE StringBase<char> StringBase<char>::operator + (const char* a_String) const
	{
		StringBase<char> result(m_Data);
		result.Append(a_String);
		return result;
	}

	TB_INLINE StringBase<char> StringBase<char>::operator + (const wchar_t* a_String) const
	{
		StringBase<char> result(m_Data);
		result.Append(a_String);
		return result;
	}

	// double width

	TB_INLINE StringBase<wchar_t> StringBase<wchar_t>::operator + (const StringBase<char>& a_String) const
	{
		StringBase<wchar_t> result(m_Data);
		result.Append(a_String.GetData());
		return result;
	}

	TB_INLINE StringBase<wchar_t> StringBase<wchar_t>::operator + (const StringBase<wchar_t>& a_String) const
	{
		StringBase<wchar_t> result(m_Data);
		result.Append(a_String.GetData());
		return result;
	}

	TB_INLINE StringBase<wchar_t> StringBase<wchar_t>::operator + (const char* a_String) const
	{
		StringBase<wchar_t> result(m_Data);
		result.Append(a_String);
		return result;
	}

	TB_INLINE StringBase<wchar_t> StringBase<wchar_t>::operator + (const wchar_t* a_String) const
	{
		StringBase<wchar_t> result(m_Data);
		result.Append(a_String);
		return result;
	}

	// ================================
	// Conversion
	// ================================


	/*template <typename C>
	TB_INLINE StringBase<C>::operator C* ()
	{
		return m_Data;
	}

	template <typename C>
	TB_INLINE StringBase<C>::operator const C* ()
	{
		return (const C*)m_Data;
	}*/

	// ================================
	// Convert to array
	// ================================

	template <>
	TB_INLINE StringBase<char>& StringBase<char>::ToCharArray(char* a_Array, unsigned int a_Maximum)
	{
		if (!m_Data && m_Length < 1) { return *this; }

		char* dst = a_Array;
		char* src = m_Data;

		for (unsigned int i = 0; i < (unsigned int)m_Length; i++)
		{
			if (i == a_Maximum - 1) 
			{
				*dst = 0;

				break; 
			}

			*dst = *src;

			dst += 1;
			src += 1;
		}

		return *this;
	}

	template <>
	TB_INLINE StringBase<wchar_t>& StringBase<wchar_t>::ToCharArray(char* a_Array, unsigned int a_Maximum)
	{
		if (!m_Data && m_Length < 1) { return *this; }

		char* dst = a_Array;
		char* src = (char*)m_Data;

		for (unsigned int i = 0; i < (unsigned int)m_Length; i++)
		{
			if (i == a_Maximum - 1) 
			{
				*dst = 0;

				break; 
			}

			*dst = *src;

			dst += 1;
			src += 2;
		}

		return *this;
	}

	template <>
	TB_INLINE StringBase<wchar_t>& tb::StringBase<wchar_t>::ToWideCharArray(wchar_t* a_Array, unsigned int a_Maximum)
	{
		if (!m_Data && m_Length < 1) { return *this; }

		wchar_t* dst = a_Array;
		wchar_t* src = m_Data;

		for (unsigned int i = 0; i < (unsigned int)m_Length; i++)
		{
			if (i == a_Maximum - 1) 
			{
				*dst = 0;

				break; 
			}

			*dst = *src;

			dst += 1;
			src += 1;
		}

		return *this;
	}

	template <>
	TB_INLINE StringBase<char>& tb::StringBase<char>::ToWideCharArray(wchar_t* a_Array, unsigned int a_Maximum)
	{
		if (!m_Data && m_Length < 1) { return *this; }

		char* dst = (char*)a_Array;
		char* src = m_Data;

		for (unsigned int i = 0; i < (unsigned int)m_Length; i++)
		{
			if (i == a_Maximum - 1) 
			{
				dst[0] = 0;
				dst[1] = 0;

				break; 
			}

			dst[0] = *src;
			dst[1] = 0;

			dst += 2;
			src += 1;
		}

		return *this;
	}

	// single width

	template <>
	TB_INLINE short StringBase<char>::ToShort(bool* a_Check /*= 0*/)
	{
		long result = atol(m_Data);
		if (a_Check) { *a_Check = true; }
		return (short)result;
	}

	template <>
	TB_INLINE unsigned short StringBase<char>::ToUShort(bool* a_Check /*= 0*/)
	{
		long result = atol(m_Data);
		if (result < 0) { result *= -1; }
		if (a_Check) { *a_Check = true; }
		return (unsigned short)result;
	}

	template <>
	TB_INLINE long StringBase<char>::ToLong(bool* a_Check /*= 0*/)
	{
		long result = atol(m_Data);
		if (a_Check) { *a_Check = true; }
		return result;
	}

	template <>
	TB_INLINE unsigned long StringBase<char>::ToULong(bool* a_Check /*= 0*/)
	{
		long result = atol(m_Data);
		if (result < 0) { result *= -1; }
		if (a_Check) { *a_Check = true; }
		return (unsigned long)result;
	}

	template <>
	TB_INLINE float StringBase<char>::ToFloat(bool* a_Check /*= 0*/)
	{
		double result = atof(m_Data);
		if (a_Check) { *a_Check = true; }
		return (float)result;
	}

	template <>
	TB_INLINE double StringBase<char>::ToDouble(bool* a_Check /*= 0*/)
	{
		double result = atof(m_Data);
		if (a_Check) { *a_Check = true; }
		return result;
	}

	// double width

	template <>
	TB_INLINE short StringBase<wchar_t>::ToShort(bool* a_Check /*= 0*/)
	{
		long result = _wtol(m_Data);
		if (a_Check) { *a_Check = true; }
		return (short)result;
	}

	template <>
	TB_INLINE unsigned short StringBase<wchar_t>::ToUShort(bool* a_Check /*= 0*/)
	{
		long result = _wtol(m_Data);
		if (result < 0) { result *= -1; }
		if (a_Check) { *a_Check = true; }
		return (unsigned short)result;
	}

	template <>
	TB_INLINE long StringBase<wchar_t>::ToLong(bool* a_Check /*= 0*/)
	{
		long result = _wtol(m_Data);
		if (a_Check) { *a_Check = true; }
		return result;
	}

	template <>
	TB_INLINE unsigned long StringBase<wchar_t>::ToULong(bool* a_Check /*= 0*/)
	{
		long result = _wtol(m_Data);
		if (result < 0) { result *= -1; }
		if (a_Check) { *a_Check = true; }
		return (unsigned long)result;
	}

	template <>
	TB_INLINE float StringBase<wchar_t>::ToFloat(bool* a_Check /*= 0*/)
	{
		double result = _wtof(m_Data);
		if (a_Check) { *a_Check = true; }
		return (float)result;
	}

	template <>
	TB_INLINE double StringBase<wchar_t>::ToDouble(bool* a_Check /*= 0*/)
	{
		double result = _wtof(m_Data);
		if (a_Check) { *a_Check = true; }
		return result;
	}

	// ================================
	// Comparison
	// ================================

	template <typename C>
	TB_INLINE bool StringBase<C>::IsEmpty() const
	{
		return (!(m_Data || m_Maximum > -1 || m_Length > -1));
	}

	template <>
	TB_INLINE bool StringBase<char>::Compare(const char* a_String, CompareMode a_Mode/* = eCompareMode_CaseSensitive*/) const
	{
		int len_left = m_Length;
		int len_right = StringHelper::GetLength<char>(a_String);
		if (len_left != len_right) { return false; }

		const char* src_left = (const char*)m_Data;
		const char* src_right = a_String;

		if (a_Mode == eCompareMode_CaseSensitive)
		{
			for (int i = 0; i < len_left; i++)
			{
				if (*src_left != *src_right) { return false; }

				src_left++;
				src_right++;
			}
		}
		else
		{
			for (int i = 0; i < len_left; i++)
			{
				char c_left = StringHelper::ToLower<char>(*src_left);
				char c_right = StringHelper::ToLower<char>(*src_right);

				if (c_left != c_right) { return false; }

				src_left++;
				src_right++;
			}
		}

		return true;
	}

	template <>
	TB_INLINE bool StringBase<wchar_t>::Compare(const wchar_t* a_String, CompareMode a_Mode/* = eCompareMode_CaseSensitive*/) const
	{
		int len_left = m_Length;
		int len_right = StringHelper::GetLength<wchar_t>(a_String);
		if (len_left != len_right) { return false; }

		const wchar_t* src_left = (const wchar_t*)m_Data;
		const wchar_t* src_right = a_String;

		if (a_Mode == eCompareMode_CaseSensitive)
		{
			for (int i = 0; i < len_left; i++)
			{
				if (*src_left != *src_right) { return false; }

				src_left++;
				src_right++;
			}
		}
		else
		{
			for (int i = 0; i < len_left; i++)
			{
				wchar_t c_left = StringHelper::ToLower<wchar_t>(*src_left);
				wchar_t c_right = StringHelper::ToLower<wchar_t>(*src_right);

				if (c_left != c_right) { return false; }

				src_left++;
				src_right++;
			}
		}

		return true;
	}

	// ================================
	// Equality operator
	// ================================

	// equal sides

	template <typename C>
	TB_INLINE bool operator == (const StringBase<C>& a_StringLeft, const StringBase<C>& a_StringRight)
	{
		int len_left = a_StringLeft.GetLength();
		int len_right = a_StringRight.GetLength();
		if (len_left != len_right || (len_left + len_right <= 0)) { return false; }

		const C* src_left = a_StringLeft.GetData();
		const C* src_right = a_StringRight.GetData();
		for (int i = 0; i < len_left; i++)
		{
			if (*src_left != *src_right) { return false; }

			src_left++;
			src_right++;
		}

		return true;
	}

	template <typename C>
	TB_INLINE bool operator == (const C* a_StringLeft, const StringBase<C>& a_StringRight)
	{
		int len_left = StringHelper::GetLength<C>(a_StringLeft);
		int len_right = a_StringRight.GetLength();
		if (len_left != len_right || (len_left + len_right <= 0)) { return false; }

		const C* src_left = a_StringLeft;
		const C* src_right = a_StringRight.GetData();
		for (int i = 0; i < len_left; i++)
		{
			if (*src_left != *src_right) { return false; }

			src_left++;
			src_right++;
		}

		return true;
	}

	template <typename C>
	TB_INLINE bool operator == (const StringBase<C>& a_StringLeft, const C* a_StringRight)
	{
		int len_left = a_StringLeft.GetLength();
		int len_right = StringHelper::GetLength<C>(a_StringRight);
		if (len_left != len_right || (len_left + len_right <= 0)) { return false; }

		const C* src_left = a_StringLeft.GetData();
		const C* src_right = a_StringRight;
		for (int i = 0; i < len_left; i++)
		{
			if (*src_left != *src_right) { return false; }

			src_left++;
			src_right++;
		}

		return true;		
	}

	// single

	template <>
	TB_INLINE bool operator == (const char* a_StringLeft, const StringBase<wchar_t>& a_StringRight)
	{
		int len_left = StringHelper::GetLength<char>(a_StringLeft);
		int len_right = a_StringRight.GetLength();
		if (len_left != len_right || (len_left + len_right <= 0)) { return false; }

		const char* src_left = a_StringLeft;
		const char* src_right = (const char*)a_StringRight.GetData();
		for (int i = 0; i < len_left; i++)
		{
			if (*src_left != *src_right) { return false; }

			src_left++;
			src_right += 2;
		}

		return true;
	}

	template <>
	TB_INLINE bool operator == (const StringBase<char>& a_StringLeft, const wchar_t* a_StringRight)
	{
		int len_left = a_StringLeft.GetLength();
		int len_right = StringHelper::GetLength<wchar_t>(a_StringRight);
		if (len_left != len_right || (len_left + len_right <= 0)) { return false; }

		const char* src_left = a_StringLeft.GetData();
		const char* src_right = (const char*)a_StringRight;
		for (int i = 0; i < len_left; i++)
		{
			if (*src_left != *src_right) { return false; }

			src_left++;
			src_right += 2;
		}

		return true;		
	}

	template <>
	TB_INLINE bool operator == (const StringBase<char>& a_StringLeft, const StringBase<wchar_t>& a_StringRight)
	{
		int len_left = a_StringLeft.GetLength();
		int len_right = a_StringRight.GetLength();
		if (len_left != len_right || (len_left + len_right <= 0)) { return false; }

		const char* src_left = a_StringLeft.GetData();
		const char* src_right = (const char*)a_StringRight.GetData();
		for (int i = 0; i < len_left; i++)
		{
			if (*src_left != *src_right) { return false; }

			src_left++;
			src_right += 2;
		}

		return true;		
	}

	// double

	template <>
	TB_INLINE bool operator == (const wchar_t* a_StringLeft, const StringBase<char>& a_StringRight)
	{
		int len_left = StringHelper::GetLength<wchar_t>(a_StringLeft);
		int len_right = a_StringRight.GetLength();
		if (len_left != len_right || (len_left + len_right <= 0)) { return false; }

		const char* src_left = (const char*)a_StringLeft;
		const char* src_right = a_StringRight.GetData();
		for (int i = 0; i < len_left; i++)
		{
			if (*src_left != *src_right) { return false; }

			src_left += 2;
			src_right++;
		}

		return true;
	}

	template <>
	TB_INLINE bool operator == (const StringBase<wchar_t>& a_StringLeft, const char* a_StringRight)
	{
		int len_left = a_StringLeft.GetLength();
		int len_right = StringHelper::GetLength<char>(a_StringRight);
		if (len_left != len_right || (len_left + len_right <= 0)) { return false; }

		const char* src_left = (const char*)a_StringLeft.GetData();
		const char* src_right = a_StringRight;
		for (int i = 0; i < len_left; i++)
		{
			if (*src_left != *src_right) { return false; }

			src_left += 2;
			src_right++;
		}

		return true;		
	}

	template <>
	TB_INLINE bool operator == (const StringBase<wchar_t>& a_StringLeft, const StringBase<char>& a_StringRight)
	{
		int len_left = a_StringLeft.GetLength();
		int len_right = a_StringRight.GetLength();
		if (len_left != len_right || (len_left + len_right <= 0)) { return false; }

		const char* src_left = (const char*)a_StringLeft.GetData();
		const char* src_right = a_StringRight.GetData();
		for (int i = 0; i < len_left; i++)
		{
			if (*src_left != *src_right) { return false; }

			src_left += 2;
			src_right++;
		}

		return true;		
	}

	// ================================
	// Inequality operator
	// ================================

	// equal sides

	template <typename C>
	TB_INLINE bool operator != (const StringBase<C>& a_StringLeft, const StringBase<C>& a_StringRight)
	{
		int len_left = a_StringLeft.GetLength();
		int len_right = a_StringRight.GetLength();
		if (len_left != len_right || len_left + len_right <= 0) { return true; }

		const C* src_left = a_StringLeft.GetData();
		const C* src_right = a_StringRight.GetData();
		for (int i = 0; i < len_left; i++)
		{
			if (*src_left != *src_right) { return true; }

			src_left++;
			src_right++;
		}

		return false;
	}

	template <typename C>
	TB_INLINE bool operator != (const C* a_StringLeft, const StringBase<C>& a_StringRight)
	{
		int len_left = StringHelper::GetLength<C>(a_StringLeft);
		int len_right = a_StringRight.GetLength();
		if (len_left != len_right || len_left + len_right <= 0) { return true; }

		const C* src_left = a_StringLeft;
		const C* src_right = a_StringRight.GetData();
		for (int i = 0; i < len_left; i++)
		{
			if (*src_left != *src_right) { return true; }

			src_left++;
			src_right++;
		}

		return false;
	}

	template <typename C>
	TB_INLINE bool operator != (const StringBase<C>& a_StringLeft, const C* a_StringRight)
	{
		int len_left = a_StringLeft.GetLength();
		int len_right = StringHelper::GetLength<C>(a_StringRight);
		if (len_left != len_right || len_left + len_right <= 0) { return true; }

		const C* src_left = a_StringLeft.GetData();
		const C* src_right = a_StringRight;
		for (int i = 0; i < len_left; i++)
		{
			if (*src_left != *src_right) { return true; }

			src_left++;
			src_right++;
		}

		return false;
	}

	// single

	template <>
	TB_INLINE bool operator != (const char* a_StringLeft, const StringBase<wchar_t>& a_StringRight)
	{
		int len_left = StringHelper::GetLength<char>(a_StringLeft);
		int len_right = a_StringRight.GetLength();
		if (len_left != len_right || len_left + len_right <= 0) { return true; }

		const char* src_left = a_StringLeft;
		const char* src_right = (const char*)a_StringRight.GetData();
		for (int i = 0; i < len_left; i++)
		{
			if (*src_left != *src_right) { return true; }

			src_left++;
			src_right += 2;
		}

		return false;
	}

	template <>
	TB_INLINE bool operator != (const StringBase<char>& a_StringLeft, const wchar_t* a_StringRight)
	{
		int len_left = a_StringLeft.GetLength();
		int len_right = StringHelper::GetLength<wchar_t>(a_StringRight);
		if (len_left != len_right || len_left + len_right <= 0) { return true; }

		const char* src_left = a_StringLeft.GetData();
		const char* src_right = (const char*)a_StringRight;
		for (int i = 0; i < len_left; i++)
		{
			if (*src_left != *src_right) { return true; }

			src_left++;
			src_right += 2;
		}

		return false;
	}

	template <>
	TB_INLINE bool operator != (const StringBase<char>& a_StringLeft, const StringBase<wchar_t>& a_StringRight)
	{
		int len_left = a_StringLeft.GetLength();
		int len_right = a_StringRight.GetLength();
		if (len_left != len_right || len_left + len_right <= 0) { return true; }

		const char* src_left = a_StringLeft.GetData();
		const char* src_right = (const char*)a_StringRight.GetData();
		for (int i = 0; i < len_left; i++)
		{
			if (*src_left != *src_right) { return true; }

			src_left++;
			src_right += 2;
		}

		return false;
	}

	// double

	template <>
	TB_INLINE bool operator != (const wchar_t* a_StringLeft, const StringBase<char>& a_StringRight)
	{
		int len_left = StringHelper::GetLength<wchar_t>(a_StringLeft);
		int len_right = a_StringRight.GetLength();
		if (len_left != len_right || len_left + len_right <= 0) { return true; }

		const char* src_left = (const char*)a_StringLeft;
		const char* src_right = a_StringRight.GetData();
		for (int i = 0; i < len_left; i++)
		{
			if (*src_left != *src_right) { return true; }

			src_left += 2;
			src_right++;
		}

		return false;
	}

	template <>
	TB_INLINE bool operator != (const StringBase<wchar_t>& a_StringLeft, const char* a_StringRight)
	{
		int len_left = a_StringLeft.GetLength();
		int len_right = StringHelper::GetLength<char>(a_StringRight);
		if (len_left != len_right || len_left + len_right <= 0) { return true; }

		const char* src_left = (const char*)a_StringLeft.GetData();
		const char* src_right = a_StringRight;
		for (int i = 0; i < len_left; i++)
		{
			if (*src_left != *src_right) { return true; }

			src_left += 2;
			src_right++;
		}

		return false;
	}

	template <>
	TB_INLINE bool operator != (const StringBase<wchar_t>& a_StringLeft, const StringBase<char>& a_StringRight)
	{
		int len_left = a_StringLeft.GetLength();
		int len_right = a_StringRight.GetLength();
		if (len_left != len_right || len_left + len_right <= 0) { return true; }

		const char* src_left = (const char*)a_StringLeft.GetData();
		const char* src_right = a_StringRight.GetData();
		for (int i = 0; i < len_left; i++)
		{
			if (*src_left != *src_right) { return true; }

			src_left += 2;
			src_right++;
		}

		return false;
	}

}